/*************************************************************************
	> File Name: cancel_cleanup.c
	> Author: 
	> Mail: 
	> Created Time: 2015年01月19日 星期一 21时48分49秒
 ************************************************************************/

#include<pthread.h>
#include"errors.h"

#define THREAD  5

// control structure shared by the test thread
// containing the synchronization and invariant data

typedef struct control_tag{
    int             counter, busy;
    pthread_mutex_t mutex;
    pthread_cond_t  cv;
} control_t;

control_t control = { 0, 1 , PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER };

void cleanup_handler(void *arg){
    control_t *st = (control_t *)arg;
    int status;

    st->counter--;
    printf("cleanup_handler: counter =  %d\n",st->counter);
    status = pthread_mutex_unlock(&st->mutex);
    if(status) err_abort(status , "Unlock in cleanup_handler");
}

void *thread_routine(void * arg){
    int status;
    
    pthread_cleanup_push(cleanup_handler,(void*)&control);

    status = pthread_mutex_lock(&control.mutex);
    if(status) err_abort(status,"mutex lock");

    control.counter++;

    while(control.busy){
        status = pthread_cond_wait(&control.cv,&control.mutex);
        if(status) err_abort(status,"Wait on condition");
    }
    pthread_cleanup_pop(1);
    return NULL;
}

int main(int argc,char *argv[]){
    pthread_t thread_id[THREAD];
    int count;
    void *result;
    int status;

    for(count = 0;count < THREAD; count++){
        status = pthread_create(&thread_id[count], NULL, thread_routine,NULL);
        if(status) err_abort(status,"Create thread");
        printf("create thread %d \n",count);
    }
    sleep(2);

    for(count = 0;count < THREAD;count++){
        status = pthread_cancel(thread_id[count]);
        if(status) err_abort(status, "Cancel thread");

        status = pthread_join(thread_id[count],&result);
        if(status) err_abort(status,"Join thread");

        if(result == PTHREAD_CANCELED)
            printf("thread %d canceled\n",count);
        else
            printf("thread %d was not canceled\n",count);
    }
    return 0;
}
